﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.Net;
using System.Collections.Generic;
using WindowsPhonePostClient;
using Newtonsoft.Json.Linq;
using DepSoft.Mobile.WP7.FollwIt.Framework;

namespace DepSoft.Mobile.WP7.FollwIt.Model
{
    public enum RestAction
    {
        GetMovieCollection,
        GetTVShowCollection,
        GetMovieSummary,
        GetTVShowSummary,
        GetUserProfile,
        PostAuthenticate,
        PostMovieBulkAction,
        PostMovieCollection,
        PostMovieUncollection,
        PostMovieWatched,
        PostMovieUnwatched,
        PostMovieUserstats,
        PostMovieRate
    }

    public class FollwItApi
    {
        #region Private members
        // Please note this is a key linked to my Depechie account!
        private readonly string _apiKey = "p7uSxaMyAoAqN";
        private readonly string _baseRestURI = @"http://follw.it/api/3/{0}/{1}";

        private string _userName = string.Empty;
        private string _password = string.Empty;
        #endregion

        #region Public properties
        public string UserName
        {
            get
            {
                return _userName;
            }
            set
            {
                _userName = value;
                Security.StoreHashedCredentials(value, this.Password);
            }
        }

        public string Password
        {
            get
            {
                return _password;
            }
            set
            {
                _password = value;
                Security.StoreHashedCredentials(this.UserName, value);
            }
        }
        #endregion

        #region Constructor
        private static FollwItApi s_Instance;
        private static object s_InstanceSync = new Object();

        /// <summary>
        /// Constructor is private, because this class has to be used as a singleton.
        /// </summary>
        protected FollwItApi()
        {
            var userName = string.Empty;
            var password = string.Empty;
            Security.RetrieveHashedCredentials(out userName, out password);

            if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
            {
                _userName = userName;
                _password = password;
            }
        }

        /// <summary>
        /// Returns an instance (a singleton)
        /// </summary>
        /// <returns>a singleton</returns>
        /// <remarks>
        /// This is an implementation of the singelton design pattern.
        /// </remarks>
        public static FollwItApi GetInstance()
        {
            // This implementation of the singleton design pattern prevents 
            // unnecessary locks (using the double if-test)
            if (s_Instance == null)
            {
                lock (s_InstanceSync)
                {
                    if (s_Instance == null)
                    {
                        s_Instance = new FollwItApi();
                    }
                }
            }
            return s_Instance;
        }
        #endregion

        #region Public methods
        public string GetActionRestURI(RestAction action, string userName = "")
        {
            switch (action)
            {
                case RestAction.PostAuthenticate:
                    return string.Format(this._baseRestURI, this._apiKey, "user.authenticate");
                    break;
                case RestAction.GetMovieCollection:
                    return string.Format(this._baseRestURI, this._apiKey, string.Format("user.movie_collection/{0}", userName));
                    break;
                case RestAction.GetTVShowCollection:
                    return string.Format(this._baseRestURI, this._apiKey, string.Format("user.tv_collection/{0}", userName));
                    break;
                case RestAction.GetMovieSummary:
                    return string.Format(this._baseRestURI, this._apiKey, "movie.summary/movie_id/en");
                    break;
                case RestAction.GetTVShowSummary:
                    //http://follw.it/api/3/p7uSxaMyAoAqN/show.summary/show_id/12806
                    return string.Format(this._baseRestURI, this._apiKey, "show.summary/show_id");
                    break;
                case RestAction.GetUserProfile:
                    return string.Format(this._baseRestURI, this._apiKey, string.Format("user.public_profile/{0}", userName));
                    break;
                case RestAction.PostMovieBulkAction:
                    //http://follw.it/api/3/apikey/movie.bulk_action
                    return string.Format(this._baseRestURI, this._apiKey, "movie.bulk_action");
                    break;
                case RestAction.PostMovieUncollection:
                    //http://follw.it/api/3/p7uSxaMyAoAqN/movie.uncollection 
                    return string.Format(this._baseRestURI, this._apiKey, "movie.uncollection");
                    break;
                case RestAction.PostMovieCollection:
                    //http://follw.it/api/3/p7uSxaMyAoAqN/movie.collection 
                    return string.Format(this._baseRestURI, this._apiKey, "movie.collection");
                    break;
                case RestAction.PostMovieUnwatched:
                    //http://follw.it/api/3/p7uSxaMyAoAqN/movie.unwatched
                    return string.Format(this._baseRestURI, this._apiKey, "movie.unwatched");
                    break;
                case RestAction.PostMovieWatched:
                    //http://follw.it/api/3/p7uSxaMyAoAqN/movie.watched
                    return string.Format(this._baseRestURI, this._apiKey, "movie.watched");
                    break;
                case RestAction.PostMovieUserstats:
                    //http://follw.it/api/3/p7uSxaMyAoAqN/movie.userstats
                    return string.Format(this._baseRestURI, this._apiKey, "movie.userstats");
                    break;
                case RestAction.PostMovieRate:
                    //http://follw.it/api/3/p7uSxaMyAoAqN/movie.rate
                    return string.Format(this._baseRestURI, this._apiKey, "movie.rate");
                    break;
                default:
                    return string.Format(this._baseRestURI, this._apiKey);
                    break;
            }
        }

        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/f9ax34y5(v=VS.95).aspx
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        public string HashPassword(string password)
        {
            string salt = "52c3a0d0-f793-46fb-a4c0-35a0ff6844c8";
            string saltedPassword = password + salt;
            SHA1Managed SHhash = new SHA1Managed();
            // Create the hash value from the array of bytes.
            byte[] HashValue = SHhash.ComputeHash(Encoding.UTF8.GetBytes(saltedPassword));
            string sHash = "";
            foreach (byte b in HashValue)
                sHash += b.ToString("x2");
            return sHash;
        }

        public event EventHandler AuthenticateCompleted;

        public void AuthenticateAsync()
        {
            JObject credentialsObject = new JObject(new JProperty("username", this.UserName),
                                                    new JProperty("password", this.HashPassword(this.Password)));

            PostClient proxy = new PostClient(credentialsObject.ToString());
            proxy.DownloadStringCompleted += (sender, e) =>
            {
                if (e.Error == null)
                {
                    //Process the result...
                    //string data = e.Result;

                    EventHandler authenticateCompleted = AuthenticateCompleted;

                    // Event will be null if there are no subscribers
                    if (authenticateCompleted != null)
                    {
                        // Use the () operator to raise the event.
                        authenticateCompleted(this, e);
                    }
                }
            };

            proxy.DownloadStringAsync(new Uri(this.GetActionRestURI(RestAction.PostAuthenticate), UriKind.Absolute));

            //string hashedPassword = HashPassword(this.Password);
            //HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(this.GetActionRestURI(RestAction.PostAuthenticate));
            //webRequest.Method = "POST";
            //webRequest.ContentLength = json.Length;
            //StreamWriter stOut = new StreamWriter(webRequest.GetRequestStream(), System.Text.Encoding.ASCII);
            //stOut.Write(json);
            //stOut.Close();
            //using (WebResponse response = webRequest.GetResponse())
            //{
            //    StreamReader sr = new StreamReader(response.GetResponseStream());
            //    string reply = sr.ReadToEnd();
            //}
        }
        #endregion
    }
}